package soulkun.library.mvvm.adapter

import androidx.annotation.NonNull
import androidx.databinding.ObservableArrayList
import androidx.databinding.ObservableList
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.adapter.FragmentStateAdapter

class BaseObservableDataFragmentStateAdapter<E : Any> : FragmentStateAdapter {

    private var dataList: ObservableArrayList<E>
    private var onFragmentCreated: ((Int) -> Fragment)
    var dataChangedListener = {

    }

    constructor(
        fragmentActivity: FragmentActivity,
        dataList: ObservableArrayList<E>,
        onFragmentCreated: (Int) -> Fragment
    ) : super(fragmentActivity) {
        this.dataList = dataList
        this.onFragmentCreated = onFragmentCreated
    }

    constructor(
        fragment: Fragment,
        dataList: ObservableArrayList<E>,
        onFragmentCreated: (Int) -> Fragment
    ) : super(fragment) {
        this.dataList = dataList
        this.onFragmentCreated = onFragmentCreated
    }

    constructor(
        fragmentManager: FragmentManager, lifecycle: Lifecycle,
        dataList: ObservableArrayList<E>,
        onFragmentCreated: (Int) -> Fragment
    ) : super(
        fragmentManager,
        lifecycle
    ) {
        this.dataList = dataList
        this.onFragmentCreated = onFragmentCreated
    }

    inner class ListChangedCallback<E : Any> :
        ObservableList.OnListChangedCallback<ObservableArrayList<E>>() {

        override fun onChanged(sender: ObservableArrayList<E>?) {
            notifyDataSetChanged()
            dataChangedListener()
        }

        override fun onItemRangeChanged(
            sender: ObservableArrayList<E>?,
            positionStart: Int,
            itemCount: Int
        ) {
            notifyItemRangeChanged(
                positionStart,
                itemCount
            )
            dataChangedListener()
        }

        override fun onItemRangeInserted(
            sender: ObservableArrayList<E>?,
            positionStart: Int,
            itemCount: Int
        ) {
            if (positionStart == 0) {
                notifyDataSetChanged()
            }else{
                notifyItemRangeInserted(
                    positionStart,
                    itemCount
                )
            }
            dataChangedListener()
        }

        override fun onItemRangeMoved(
            sender: ObservableArrayList<E>?,
            fromPosition: Int,
            toPosition: Int,
            itemCount: Int
        ) {
            if (itemCount == 1) {
                notifyItemMoved(fromPosition, toPosition)
            } else {
                notifyDataSetChanged()
            }
            dataChangedListener()
        }

        override fun onItemRangeRemoved(
            sender: ObservableArrayList<E>?,
            positionStart: Int,
            itemCount: Int
        ) {
            if (positionStart == 0 && dataList.size == 0) {
                notifyDataSetChanged()
            } else {
                if (itemCount == 1) {
                    notifyItemRemoved(positionStart)
                } else {
                    notifyItemRangeRemoved(
                        positionStart,
                        itemCount
                    )
                }
            }
            dataChangedListener()
        }
    }

    private val listChangedCallback = ListChangedCallback<E>()

    override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
        super.onAttachedToRecyclerView(recyclerView)
        dataList.addOnListChangedCallback(listChangedCallback)
    }

    override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
        super.onDetachedFromRecyclerView(recyclerView)
        dataList.removeOnListChangedCallback(listChangedCallback)
    }

    override fun getItemCount(): Int {
        return dataList.size
    }

    override fun createFragment(position: Int): Fragment {
        return onFragmentCreated(position)
    }

    override fun getItemId(position: Int): Long {
        return dataList[position].hashCode().toLong()
    }

    override fun containsItem(itemId: Long): Boolean {
        return dataList.map { it.hashCode().toLong() }.contains(itemId)
    }

}